import mdl
_App = mdl._App
toast = mdl.toast
Section = mdl.Section
Center = mdl.Center
Container = mdl.Container
Column = mdl.Column
Row = mdl.Row
Text = mdl.Text
Badge = mdl.Badge
Textfield = mdl.Textfield
EdgeInsets = mdl.EdgeInsets
Themes = mdl.Themes
Dialog = mdl.Dialog
Card = mdl.Card
CardTitle = mdl.CardTitle
CardText = mdl.CardText
CardAction = mdl.CardAction
Colors = mdl.Colors
Table = mdl.Table
Button = mdl.Button
Icon = mdl.Icon
IconToggle = mdl.IconToggle
Switch = mdl.Switch
Footer = mdl.Footer
FooterLeft = mdl.FooterLeft
Slider = mdl.Slider
MainAxisSize = mdl.MainAxisSize
MainAxisAlignment = mdl.MainAxisAlignment
CrossAxisAlignment = mdl.CrossAxisAlignment
BorderRadius = mdl.BorderRadius
Image = mdl.Image
List = mdl.List
ListItem = mdl.ListItem
BoxShadow = mdl.BoxShadow
Offset = mdl.Offset
maketag = mdl.maketag

js = javascript
doc = js.document

import ajax
import random

class SudokuBox:
	def render(self, parent, size=35):
		self.cells = [[None for j in range(9)] for i in range(9)]
		elt = maketag('div', style={'display':'flex', 'flex-direction':' column', 'margin':'20px'})
		parent.appendChild(elt)
		def on_input(ev):
			text = ev.target.innerText.data()
			t = ''.join([c for c in text if c in ' 123456789'])
			if len(t)>1:
				t = t[-1]
			if t!=text:
				p = ev.target
				p.innerText = t
				s = js.window.getSelection()
				r = js.document.createRange()
				r.setStart(p, len(t))
				r.setEnd(p, len(t))
				s.removeAllRanges()
				s.addRange(r)
				ev.preventDefault()
		for i in range(9):
			row = maketag('div', style={'display':'flex', 'flex-direction':' row'})
			elt.appendChild(row)
			for j in range(9):
				style = {'width':f'{size}px', 'height':f'{size}px', 'text-align':'center', 'line-height':f'{size}px', 'border-style':'solid', 'border-color':'#ccc', 'background-color':'#fff', 'outline':'0px solid transparent'}
				if (i==0) and (j==0):
					style['border-radius'] = '30% 0 0 0'
				elif (i==0) and (j==8):
					style['border-radius'] = '0 30% 0 0'
				elif (i==8) and (j==8):
					style['border-radius'] = '0 0 30% 0'
				elif (i==8) and (j==0):
					style['border-radius'] = '0 0 0 30%'
				border = ['1px','0','0','1px']
				if (i%3)==0:
					border[0] = '2px'
				elif i==8:
					border[2] = '2px'
				if (j%3)==0:
					border[3] = '2px'
				elif j==8:
					border[1] = '2px'
				style['border-width'] = ' '.join(border)
				# 'border':'solid 1px #ccc', 'display':'flex', 'flex-direction':' column', 'justify-content':'space-around'
				cell = maketag('div', {'contenteditable':'plaintext-only'}, style=style)
				self.cells[i][j] = cell
				cell.bind('input', on_input)
				row.appendChild(cell)
		return elt

	def setContentEditable(self, editable):
		if isinstance(editable, bool):
			editable = [[editable for j in range(9)] for i in range(9)]
		for i in range(9):
			for j in range(9):
				c = self.cells[i][j]
				e = editable[i][j]
				if isinstance(e,int):
					e = (e==0)
				assert isinstance(e,bool)
				if e:
					c.setAttribute('contenteditable', 'plaintext-only')
					c.style['font-weight'] = 'normal'
					c.style['color'] = '#000'
				else:
					c.setAttribute('contenteditable', 'false')
					c.style['font-weight'] = 'bold'
					c.style['color'] = '#CC6600'

	def setContent(self, content):
		if isinstance(content, int):
			content = [[content for j in range(9)] for i in range(9)]
		for i in range(9):
			for j in range(9):
				c = content[i][j]
				assert isinstance(c,int)
				c = '' if c==0 else str(c)
				self.cells[i][j].innerText = c

	def getContent(self):
		content = [[0 for j in range(9)] for i in range(9)]
		for i in range(9):
			for j in range(9):
				d = self.cells[i][j].innerText.data().strip()
				content[i][j] = 0 if len(d)==0 else int(d)
		return content

def 解答(box):
	dialog = Dialog(actions_full_width=True, title='帮助', actions=['擦除答案', '擦除错误', '填入答案', '取消'])
	dialog.render(doc.body)
	def action(ev):
		global cur_sudoku, info_dialog
		res = dialog.show()
		if res=='擦除答案':
			if cur_sudoku is not None:
				box.setContent(cur_sudoku)
			else:
				box.setContent(0)
		if res=='擦除错误':
			if cur_sudoku is None:
				info_dialog.show('还没生成题目', '错误')
				return
			solutions = ajax.rpc.search(cur_sudoku)
			if len(solutions)==0:
				info_dialog.show('题目无解', '错误')
			if len(solutions)>1:
				info_dialog.show('题目存在多个解', '错误')
			_, solution = solutions[0]
			content = box.getContent()
			for i in range(9):
				for j in range(9):
					if content[i][j]!=solution[i][j]:
						content[i][j] = 0
			box.setContent(content)
		if res=='填入答案':
			if cur_sudoku is None:
				info_dialog.show('还没生成题目', '错误')
				return
			solutions = ajax.rpc.search(cur_sudoku)
			if len(solutions)==0:
				info_dialog.show('题目无解', '错误')
			if len(solutions)>1:
				info_dialog.show('题目存在多个解', '错误')
			_, solution = solutions[0]
			box.setContent(solution)
			if len(solutions)==0:
				info_dialog.show('题目无解', '错误')
			if len(solutions)>1:
				info_dialog.show('题目存在多个解', '错误')
	return Column(
		box,
		Button('帮助', raised=True, primary=True, action=action),
		margin=EdgeInsets.all(10),
		)

def 生成(box):
	gen_box = SudokuBox()
	gen_dialog = Dialog(actions_full_width=True, title='生成', actions=['生成简单', '生成普通', '生成难题', '取消'])
	gen_dialog.render(doc.body)
	clear_dialog = Dialog(actions_full_width=True, title='擦除', actions=['擦除题目', '取消'])
	clear_dialog.render(doc.body)
	apply_dialog = Dialog(actions_full_width=True, title='应用', actions=['应用题目', '取消'])
	apply_dialog.render(doc.body)
	def setContent(content):
		box.setContent(content)
		box.setContentEditable(content)
		global cur_sudoku
		cur_sudoku = content
	def simplify_content(content, level):
		solution = ajax.rpc.search(content)
		solution = solution[0][1]
		ps = []
		for i in range(9):
			for j in range(9):
				if content[i][j]==0:
					ps.append([i,j,solution[i][j]])
		random.shuffle(ps)
		to_add = level-(81-len(ps))
		if to_add>0:
			ps = ps[:to_add]
			for i,j,d in ps:
				content[i][j] = d
		return content
	def gen_action(ev):
		res = gen_dialog.show()
		if res=='取消':
			return
		level = {'生成简单':40, '生成普通':30, '生成难题':20}[res]
		gen_box.setContent(0)
		content = ajax.rpc.random_sukodu()
		content = simplify_content(content, level)
		gen_box.setContent(content)
	def clear_action(ev):
		res = clear_dialog.show()
		if res=='擦除题目':
			gen_box.setContent(0)
	def apply_action(ev):
		res = apply_dialog.show()
		if res=='应用题目':
			content = gen_box.getContent()
			setContent(content)
	gen = Button('生成', raised=True, primary=True, action=gen_action)
	clear = Button('擦除', raised=True, primary=True, action=clear_action)
	apply = Button('应用', raised=True, primary=True, action=apply_action)
	return Column(
		gen_box,
		Row(gen, clear, apply),
		margin=EdgeInsets.all(10),
		)

info_dialog = None
cur_sudoku = None
def run_app():
	Themes(primary='amber', accent='red').apply()
	# text = Textfield(label="测试用密码", password=True, floating_label=True)
	box = SudokuBox()
	global info_dialog
	info_dialog = Dialog(actions_full_width=True, actions=['确定'])
	info_dialog.render(doc.body)
	app = _App(title="数独",
				app_icon="/web/🤖.png",
				fixed_header=True,
				sections=[
					Section('生成', 生成(box)),
					Section('解答', 解答(box)),
					],
				)
	app.render(doc.body)

run_app()
